home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / PPPIPCP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-23  |  29.0 KB  |  1,079 lines

  1. /*
  2.  *  PPPIPCP.C    -- negotiate IP parameters
  3.  *
  4.  *    This implementation of PPP is declared to be in the public domain.
  5.  *
  6.  *    Jan 91    Bill_Simpson@um.cc.umich.edu
  7.  *        Computer Systems Consulting Services
  8.  *
  9.  *    Acknowledgements and correction history may be found in PPP.C
  10.  */
  11.  
  12. #include "global.h"
  13. #ifdef PPP
  14. #include "mbuf.h"
  15. #include "iface.h"
  16. #include "slhc.h"
  17. #include "ppp.h"
  18. #include "pppfsm.h"
  19. #include "pppipcp.h"
  20. #include "cmdparse.h"
  21. #include "files.h"
  22. #include "trace.h"
  23.  
  24.  
  25. #if !defined(_lint)
  26. static char rcsid[] OPTIONAL = "$Id: pppipcp.c,v 1.12 1996/12/23 20:37:36 root Exp root $";
  27. #endif
  28.  
  29. /* These defaults are defined in the PPP RFCs, and must not be changed */
  30. static struct ipcp_value_s ipcp_default =
  31. {
  32.     FALSE,            /* no need to negotiate defaults */
  33.  
  34.     0L,            /* no source address */
  35.     0L,            /* no destination address */
  36.  
  37.     0,            /* no compression protocol */
  38.     0,            /* no slots */
  39.     0            /* no slot compression */
  40. };
  41.  
  42. /* for test purposes, accept anything we understand */
  43. static int16 ipcp_negotiate = IPCP_N_ADDRESSES | IPCP_N_COMPRESS | IPCP_N_ADDRESS;
  44.  
  45. static byte_t option_length[] =
  46. {
  47.     0,            /* unused */
  48.     10,            /* ip addresses */
  49.     6,            /* compression */
  50.     6            /* ip address */
  51. };
  52.  
  53.  
  54. static int doipcp_local (int argc, char *argv[], void *p);
  55. static int doipcp_open (int argc, char *argv[], void *p);
  56. static int doipcp_pool (int argc, char *argv[], void *p);
  57. static int doipcp_remote (int argc, char *argv[], void *p);
  58.  
  59. static int doipcp_address (int argc, char *argv[], void *p);
  60. static int doipcp_compress (int argc, char *argv[], void *p);
  61. static int doipcp_default (int argc, char *argv[], void *p);
  62.  
  63. static void ipcp_option (struct mbuf ** bpp, struct ipcp_value_s * value_p,
  64.     byte_t o_type, byte_t o_length, struct mbuf ** copy_bpp);
  65. static void ipcp_makeoptions (struct mbuf ** bpp, struct ipcp_value_s * value_p, int16 negotiating);
  66. static struct mbuf *ipcp_makereq (struct fsm_s * fsm_p);
  67.  
  68. static int ipcp_check (struct mbuf ** bpp, struct ipcp_s * ipcp_p,
  69.     struct ipcp_side_s * side_p, struct option_hdr * option_p, int request);
  70.  
  71. static int ipcp_request (struct fsm_s * fsm_p, struct config_hdr * config, struct mbuf * data);
  72. static int ipcp_ack (struct fsm_s * fsm_p, struct config_hdr * config, struct mbuf * data);
  73. static int ipcp_nak (struct fsm_s * fsm_p, struct config_hdr * config, struct mbuf * data);
  74. static int ipcp_reject (struct fsm_s * fsm_p, struct config_hdr * config, struct mbuf * data);
  75.  
  76. static void ipcp_reset (struct fsm_s * fsm_p);
  77.  
  78. static uint32 ipcp_addr_idle (uint32 addr);
  79. static uint32 ipcp_lookuppeer (char *peerid);
  80. static uint32 ipcp_poolnext (struct ipcp_s * ipcp_p);
  81.  
  82. static void ipcp_starting (struct fsm_s * fsm_p);
  83. static void ipcp_stopping (struct fsm_s * fsm_p);
  84.  
  85. static void ipcp_closing (struct fsm_s * fsm_p);
  86. static void ipcp_opening (struct fsm_s * fsm_p);
  87.  
  88. static void ipcp_free (struct fsm_s * fsm_p);
  89.  
  90.  
  91. static struct fsm_constant_s ipcp_constants =
  92. {
  93.     "IPcp",
  94.     PPP_IPCP_PROTOCOL,
  95.     0x00FE,            /* codes 1-7 recognized */
  96.  
  97.     IPcp,
  98.     IPCP_REQ_TRY,
  99.     IPCP_NAK_TRY,
  100.     IPCP_TERM_TRY,
  101.     IPCP_TIMEOUT * 1000L,
  102.  
  103.     ipcp_free,
  104.  
  105.     ipcp_reset,
  106.     ipcp_starting,
  107.     ipcp_opening,
  108.     ipcp_closing,
  109.     ipcp_stopping,
  110.  
  111.     ipcp_makereq,
  112.     ipcp_request,
  113.     ipcp_ack,
  114.     ipcp_nak,
  115.     ipcp_reject,
  116. };
  117.  
  118.  
  119. /************************************************************************/
  120.  
  121. /* "ppp <iface> ipcp" subcommands */
  122. static struct cmds IPcpcmds[] =
  123. {
  124.     { "close",    doppp_close,    0, 0, NULLCHAR },
  125.     { "listen",    doppp_passive,    0, 0, NULLCHAR },
  126.     { "local",    doipcp_local,    0, 0, NULLCHAR },
  127.     { "open",    doipcp_open,    0, 0, NULLCHAR },
  128.     { "pool",    doipcp_pool,    0, 0, NULLCHAR },
  129.     { "remote",    doipcp_remote,    0, 0, NULLCHAR },
  130.     { "timeout",    doppp_timeout,    0, 0, NULLCHAR },
  131.     { "try",    doppp_try,    0, 0, NULLCHAR },
  132.     { NULLCHAR,    0,        0, 0, NULLCHAR }
  133. };
  134.  
  135.  
  136. /* { "ppp <iface> ipcp {local | remote}" subcommands */
  137. static struct cmds IPcpside_cmds[] =
  138. {
  139.     { "address",    doipcp_address,        0, 0, NULLCHAR },
  140.     { "compress",    doipcp_compress,    0, 0, NULLCHAR },
  141.     { "default",    doipcp_default,        0, 0, NULLCHAR },
  142.     { NULLCHAR,    0,            0, 0, NULLCHAR }
  143. };
  144.  
  145.  
  146.  
  147. int
  148. doppp_ipcp (int argc, char *argv[], void *p)
  149. {
  150. register struct iface *ifp = p;
  151. register struct ppp_s *ppp_p = ifp->edv;
  152.  
  153.     return subcmd (IPcpcmds, argc, argv, &(ppp_p->fsm[IPcp]));
  154. }
  155.  
  156.  
  157.  
  158. static int
  159. doipcp_local (int argc, char *argv[], void *p)
  160. {
  161. struct fsm_s *fsm_p = p;
  162. struct ipcp_s *ipcp_p = fsm_p->pdv;
  163.  
  164.     return subcmd (IPcpside_cmds, argc, argv, &(ipcp_p->local));
  165. }
  166.  
  167.  
  168.  
  169. static int
  170. doipcp_open (int argc, char *argv[], void *p)
  171. {
  172. struct fsm_s *fsm_p = p;
  173.  
  174.     (void) doppp_active (argc, argv, p);
  175.  
  176.     if (fsm_p->ppp_p->phase == pppREADY)
  177.         fsm_start (fsm_p);
  178.  
  179.     return 0;
  180. }
  181.  
  182.  
  183.  
  184. /* Set a pool of peer addresses for PPP interface */
  185. static int
  186. doipcp_pool (int argc, char *argv[], void *p)
  187. {
  188. struct fsm_s *fsm_p = p;
  189. struct ipcp_s *ipcp_p = fsm_p->pdv;
  190. uint32 pool_addr;
  191. int pool_cnt;
  192.  
  193.     if (argc < 2) {
  194.         if (ipcp_p->peer_min == 0L)
  195.             tputs ("None");
  196.         else {
  197.             tprintf ("%s thru ", inet_ntoa (ipcp_p->peer_min));
  198.             tprintf ("%s\n", inet_ntoa (ipcp_p->peer_max));
  199.         }
  200.         return 0;
  201.     }
  202.     if ((pool_addr = resolve (argv[1])) == 0L)
  203.         tprintf (Badhost, argv[1]);
  204.  
  205.     /* May specify a consecutive range of addresses; otherwise assume 1 */
  206.     if (argc < 3)
  207.         pool_cnt = 1;
  208.     else
  209.         pool_cnt = (int) strtol (argv[2], NULLCHARP, 0);
  210.  
  211.     if (pool_cnt <= 0) {
  212.         tprintf ("Pool count %s (%d) must be > 0\n", argv[2], pool_cnt);
  213.         return -1;
  214.     }
  215.     ipcp_p->peer_min = pool_addr;
  216.     ipcp_p->peer_max = pool_addr + (unsigned long) pool_cnt - 1;
  217.     return 0;
  218. }
  219.  
  220.  
  221.  
  222. static int
  223. doipcp_remote (int argc, char *argv[], void *p)
  224. {
  225. struct fsm_s *fsm_p = p;
  226. struct ipcp_s *ipcp_p = fsm_p->pdv;
  227.  
  228.     return subcmd (IPcpside_cmds, argc, argv, &(ipcp_p->remote));
  229. }
  230.  
  231.  
  232.  
  233. /************************************************************************/
  234. /* Set addresses for PPP interface */
  235. static int
  236. doipcp_address (int argc, char *argv[], void *p)
  237. {
  238. struct ipcp_side_s *side_p = p;
  239. uint32 x32;
  240.  
  241.     if (argc < 2) {
  242.         tprintf ("%s\n", inet_ntoa (side_p->want.address));
  243.         return 0;
  244.     } else if (stricmp (argv[1], "allow") == 0)
  245.         return bit16cmd (&(side_p->will_negotiate), IPCP_N_ADDRESSES, "Allow Address", --argc, &argv[1]);
  246.  
  247.     if ((x32 = resolve (argv[1])) == 0L)
  248.         tprintf (Badhost, argv[1]);
  249.  
  250.     side_p->want.address = x32;
  251.     side_p->want.negotiate |= IPCP_N_ADDRESSES;
  252.     return 0;
  253. }
  254.  
  255.  
  256.  
  257. /* Set IP compression type for PPP interface */
  258. static int
  259. doipcp_compress (int argc, char *argv[], void *p)
  260. {
  261. struct ipcp_side_s *side_p = p;
  262.  
  263.     if (argc < 2) {
  264.         if (side_p->want.negotiate & IPCP_N_COMPRESS) {
  265.             switch (side_p->want.compression) {
  266.                 case PPP_COMPR_PROTOCOL:
  267.                     tprintf ("TCP header compression enabled; Slots = %d, slot compress = %x\n",
  268.                         side_p->want.slots, side_p->want.slot_compress);
  269.                     break;
  270.                 default:
  271.                     tprintf ("0x%04x\n", side_p->want.compression);
  272.                     break;
  273.             }
  274.         } else
  275.             tputs ("None\n");
  276.     } else if (stricmp (argv[1], "allow") == 0)
  277.         return bit16cmd (&(side_p->will_negotiate), IPCP_N_COMPRESS,
  278.             "Allow Compression", --argc, &argv[1]);
  279.     else if (stricmp (argv[1], "tcp") == 0 || stricmp (argv[1], "vj") == 0) {
  280.         side_p->want.compression = PPP_COMPR_PROTOCOL;
  281.         if (argc >= 3) {
  282.             side_p->want.slots = (int16) strtol (argv[2], NULLCHARP, 0);
  283.             if (side_p->want.slots < 1 || side_p->want.slots > 255) {
  284.                 tputs ("slots must be in range 1 to 255");
  285.                 return 1;
  286.             }
  287.         } else
  288.             side_p->want.slots = IPCP_SLOT_DEFAULT;
  289.  
  290.         if (argc >= 4)
  291.             side_p->want.slot_compress = uchar (strtol (argv[3], NULLCHARP, 0));
  292.         else
  293.             side_p->want.slot_compress = IPCP_SLOT_COMPRESS;
  294.  
  295.         side_p->want.negotiate |= IPCP_N_COMPRESS;
  296.     } else if (stricmp (argv[1], "none") == 0)
  297.         side_p->want.negotiate &= ~IPCP_N_COMPRESS;
  298.     else {
  299.         tputs ("allow tcp none\n");
  300.         return 1;
  301.     }
  302.     return 0;
  303. }
  304.  
  305.  
  306.  
  307. static int
  308. doipcp_default (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
  309. {
  310. struct ipcp_side_s *side_p = p;
  311.  
  312.     ASSIGN (side_p->want, ipcp_default);
  313.     return 0;
  314. }
  315.  
  316.  
  317.  
  318. /************************************************************************/
  319. /*            E V E N T   P R O C E S S I N G            */
  320. /************************************************************************/
  321.  
  322. static void
  323. ipcp_option (
  324. struct mbuf **bpp,
  325. struct ipcp_value_s *value_p,
  326. byte_t o_type,
  327. byte_t o_length,
  328. struct mbuf **copy_bpp
  329. ) {
  330. struct mbuf *bp;
  331. register unsigned char *cp;
  332. register int toss = o_length - OPTION_HDR_LEN;
  333.  
  334.     if ((bp = alloc_mbuf (o_length)) == NULLBUF)
  335.         return;
  336.  
  337.     cp = bp->data;
  338.     *cp++ = o_type;
  339.     *cp++ = o_length;
  340.  
  341.     switch (o_type) {
  342.         case IPCP_ADDRESSES:
  343.             cp = put32 (cp, value_p->address);
  344.             cp = put32 (cp, value_p->other);
  345.             toss -= 8;
  346. #ifdef PPP_DEBUG_OPTIONS
  347.             if (PPPtrace & PPP_DEBUG_OPTIONS) {
  348.                 trace_log (PPPiface, "    making IP source address: %s",
  349.                     inet_ntoa (value_p->address));
  350.                 trace_log (PPPiface, "    making IP destination address %s",
  351.                     inet_ntoa (value_p->other));
  352.             }
  353. #endif
  354.             break;
  355.  
  356.         case IPCP_COMPRESS:
  357.             cp = put16 (cp, value_p->compression);
  358.             toss -= 2;
  359. #ifdef PPP_DEBUG_OPTIONS
  360.             if (PPPtrace & PPP_DEBUG_OPTIONS)
  361.                 trace_log (PPPiface, "    making IP compression 0x%04x",
  362.                     value_p->compression);
  363. #endif
  364.             if (value_p->compression == PPP_COMPR_PROTOCOL) {
  365.                 *cp++ = uchar (value_p->slots - 1);
  366.                 *cp++ = value_p->slot_compress;
  367.                 toss -= 2;
  368. #ifdef PPP_DEBUG_OPTIONS
  369.                 if (PPPtrace & PPP_DEBUG_OPTIONS)
  370.                     trace_log (PPPiface, "    with IP compression slots %d, flag %x",
  371.                         value_p->slots, value_p->slot_compress);
  372. #endif
  373.             }
  374.             break;
  375.  
  376.         case IPCP_ADDRESS:          /* Added By LAK */
  377.             cp = put32(cp, value_p->address);
  378.             toss -= 4;
  379. #ifdef PPP_DEBUG_OPTIONS
  380.             if (PPPtrace & PPP_DEBUG_OPTIONS)
  381.                 trace_log(PPPiface, "    making IP source address: %s",
  382.                     inet_ntoa(value_p->address));
  383. #endif
  384.             break;
  385.         
  386.         default:
  387. #ifdef PPP_DEBUG_OPTIONS
  388.             if (PPPtrace & PPP_DEBUG_OPTIONS)
  389.                 trace_log (PPPiface, "    making unimplemented type %d", o_type);
  390. #endif
  391.             break;
  392.     }
  393.  
  394.     while (toss-- > 0)
  395.         *cp++ = uchar (pullchar (copy_bpp));
  396.  
  397.     bp->cnt += o_length;
  398.     append (bpp, bp);
  399. }
  400.  
  401.  
  402.  
  403. /************************************************************************/
  404. /* Build a list of options */
  405. static void
  406. ipcp_makeoptions (struct mbuf **bpp, struct ipcp_value_s *value_p, int16 negotiating)
  407. {
  408. register int o_type;
  409.  
  410.     PPP_DEBUG_ROUTINES ("ipcp_makeoptions()");
  411.  
  412.     for (o_type = 1; o_type <= IPCP_OPTION_LIMIT; o_type++) {
  413.         if (negotiating & (1 << o_type))
  414.             ipcp_option (bpp, value_p, uchar (o_type), option_length[o_type], NULLBUFP);
  415.     }
  416. }
  417.  
  418.  
  419.  
  420. /************************************************************************/
  421. /* Build a request to send to remote host */
  422. static struct mbuf *
  423. ipcp_makereq (struct fsm_s *fsm_p)
  424. {
  425. struct ipcp_s *ipcp_p = fsm_p->pdv;
  426. struct mbuf *req_bp = NULLBUF;
  427.  
  428.     PPP_DEBUG_ROUTINES ("ipcp_makereq()");
  429.  
  430.     ipcp_makeoptions (&req_bp, &(ipcp_p->local.work), ipcp_p->local.work.negotiate);
  431.     return (req_bp);
  432. }
  433.  
  434.  
  435.  
  436. /************************************************************************/
  437. /* Check the options, updating the working values.
  438.  * Returns -1 if ran out of data, ACK/NAK/REJ as appropriate.
  439.  */
  440. static int
  441. ipcp_check (
  442. struct mbuf **bpp,
  443. struct ipcp_s *ipcp_p,
  444. struct ipcp_side_s *side_p,
  445. struct option_hdr *option_p,
  446. int request
  447. ) {
  448. int toss = option_p->len - OPTION_HDR_LEN;
  449. int option_result = CONFIG_ACK;    /* Assume good values */
  450. int test;
  451.  
  452.     switch (option_p->type) {
  453.         case IPCP_ADDRESSES:
  454.             side_p->work.address = pull32 (bpp);
  455.             side_p->work.other = pull32 (bpp);
  456.             toss -= 8;
  457. #ifdef PPP_DEBUG_OPTIONS
  458.             if (PPPtrace & PPP_DEBUG_OPTIONS) {
  459.                 trace_log (PPPiface, "    checking IP source address: %s",
  460.                     inet_ntoa (side_p->work.address));
  461.                 trace_log (PPPiface, "    checking IP destination address %s",
  462.                     inet_ntoa (side_p->work.other));
  463.             }
  464. #endif
  465.             if (!request) {
  466.                 /* override any undesirable changes */
  467.                 if (ipcp_p->remote.want.address != 0L)
  468.                     ipcp_p->local.work.other = ipcp_p->remote.want.address;
  469.  
  470.                 if (ipcp_p->local.want.address != 0L)
  471.                     ipcp_p->local.work.address = ipcp_p->local.want.address;
  472.  
  473.                 break;
  474.             }
  475.             /* Ensure that addresses match */
  476.             if (ipcp_p->remote.work.address == ipcp_p->remote.want.address) {
  477.                 if (ipcp_p->remote.want.address == 0L)
  478.                     /* don't know address either */
  479.                     option_result = CONFIG_REJ;
  480.  
  481.             } else if (ipcp_p->remote.want.address == 0L)
  482.                 ipcp_p->local.work.other = ipcp_p->remote.work.address;
  483.             else {
  484.                 ipcp_p->remote.work.address = ipcp_p->remote.want.address;
  485.                 option_result = CONFIG_NAK;
  486.             }
  487.  
  488.             if (ipcp_p->remote.work.other == ipcp_p->local.want.address) {
  489.                 if (ipcp_p->local.want.address == 0L)
  490.                     /* don't know address either */
  491.                     option_result = CONFIG_REJ;
  492.  
  493.             } else if (ipcp_p->local.want.address == 0L)
  494.                 ipcp_p->local.work.address = ipcp_p->remote.work.other;
  495.             else {
  496.                 option_result = CONFIG_NAK;
  497.                 ipcp_p->remote.work.other = ipcp_p->local.want.address;
  498.             }
  499.             break;
  500.  
  501.         case IPCP_COMPRESS:
  502.             side_p->work.compression = pull16 (bpp);
  503.             toss -= 2;
  504. #ifdef PPP_DEBUG_OPTIONS
  505.             if (PPPtrace & PPP_DEBUG_OPTIONS)
  506.                 trace_log (PPPiface, "    checking IP compression 0x%04x",
  507.                     side_p->work.compression);
  508. #endif
  509.             /* Check if requested type is acceptable */
  510.             switch (side_p->work.compression) {
  511.                 case PPP_COMPR_PROTOCOL:
  512.                     if ((test = pullchar (bpp)) == -1)
  513.                         return -1;
  514.  
  515.                     if ((side_p->work.slots = (int16) (test + 1)) < IPCP_SLOT_LO) {
  516.                         side_p->work.slots = IPCP_SLOT_LO;
  517.                         option_result = CONFIG_NAK;
  518.                     } else if (side_p->work.slots > IPCP_SLOT_HI) {
  519.                         side_p->work.slots = IPCP_SLOT_HI;
  520.                         option_result = CONFIG_NAK;
  521.                     }
  522.                     if ((test = pullchar (bpp)) == -1)
  523.                         return -1;
  524.  
  525.                     if ((side_p->work.slot_compress = uchar (test)) > 1) {
  526.                         side_p->work.slot_compress = 1;
  527.                         option_result = CONFIG_NAK;
  528.                     }
  529.                     toss -= 2;
  530. #ifdef PPP_DEBUG_OPTIONS
  531.                     if (PPPtrace & PPP_DEBUG_OPTIONS)
  532.                         trace_log (PPPiface, "    with IP compression slots %d, flag %x",
  533.                             side_p->work.slots,
  534.                         side_p->work.slot_compress);
  535. #endif
  536.                     break;
  537.  
  538.                 default:
  539.                     if (side_p->want.negotiate & IPCP_N_COMPRESS) {
  540.                         side_p->work.compression = side_p->want.compression;
  541.                         side_p->work.slots = side_p->want.slots;
  542.                         side_p->work.slot_compress = side_p->want.slot_compress;
  543.                     } else {
  544.                         side_p->work.compression = PPP_COMPR_PROTOCOL;
  545.                         side_p->work.slots = IPCP_SLOT_DEFAULT;
  546.                         side_p->work.slot_compress = IPCP_SLOT_COMPRESS;
  547.                     }
  548.                     option_result = CONFIG_NAK;
  549.                     break;
  550.             }
  551.             break;
  552.  
  553.         case IPCP_ADDRESS:        /* Added By LAK */
  554.             side_p->work.address = pull32(bpp);
  555.             toss -= 4;
  556. #ifdef PPP_DEBUG_OPTIONS
  557.             if (PPPtrace & PPP_DEBUG_OPTIONS)
  558.                 trace_log(PPPiface, "    checking IP source address: %s",
  559.                     inet_ntoa(side_p->work.address));
  560. #endif
  561.             if ( !request )        {
  562.                 /* override any undesirable changes */
  563.                 if (ipcp_p->local.want.address != 0L)
  564.                     ipcp_p->local.work.address = ipcp_p->local.want.address;
  565.                 break;
  566.             }
  567.  
  568.             if (ipcp_p->remote.work.other == ipcp_p->local.want.address)    {
  569.                 if (ipcp_p->local.want.address == 0L)
  570.                     /* don't know address either */
  571.                     option_result = CONFIG_REJ;
  572.             } else if (ipcp_p->local.want.address == 0L)
  573.                 ipcp_p->local.work.address = ipcp_p->remote.work.other;
  574.             else    {
  575.                 option_result = CONFIG_NAK;
  576.                 ipcp_p->remote.work.other = ipcp_p->local.want.address;
  577.             }
  578.             break;
  579.  
  580.         default:
  581.             option_result = CONFIG_REJ;
  582.             break;
  583.     }
  584.  
  585.     if (option_p->type > IPCP_OPTION_LIMIT || !(side_p->will_negotiate & (1 << option_p->type)))
  586.         option_result = CONFIG_REJ;
  587.  
  588.     if (toss < 0)
  589.         return -1;
  590.  
  591.     if (!request && toss > 0) {
  592.         /* toss extra bytes in option */
  593.         while (toss-- > 0) {
  594.             if (pullchar (bpp) == -1)
  595.                 return -1;
  596.         }
  597.     }
  598.     return (option_result);
  599. }
  600.  
  601.  
  602.  
  603. /************************************************************************/
  604. /* Check options requested by the remote host */
  605. static int
  606. ipcp_request (struct fsm_s *fsm_p, struct config_hdr *config, struct mbuf *data)
  607. {
  608. struct ipcp_s *ipcp_p = fsm_p->pdv;
  609. int32 signed_length = config->len;
  610. struct mbuf *reply_bp = NULLBUF;    /* reply packet */
  611. int reply_result = CONFIG_ACK;    /* reply to request */
  612. int16 desired;        /* desired to negotiate */
  613. struct option_hdr option;    /* option header storage */
  614. int option_result;    /* option reply */
  615.  
  616.     PPP_DEBUG_ROUTINES ("ipcp_request()");
  617.     ipcp_p->remote.work.negotiate = FALSE;    /* clear flags */
  618.  
  619.     /* Process options requested by remote host */
  620.     while (signed_length > 0 && ntohopt (&option, &data) != -1) {
  621.         if ((signed_length -= option.len) < 0) {
  622.             PPP_DEBUG_CHECKS ("IPCP REQ: bad header length");
  623.             free_p (data);
  624.             free_p (reply_bp);
  625.             return -1;
  626.         }
  627.         if ((option_result = ipcp_check (&data, ipcp_p, &(ipcp_p->remote), &option, TRUE)) == -1) {
  628.             PPP_DEBUG_CHECKS ("IPCP REQ: ran out of data");
  629.             free_p (data);
  630.             free_p (reply_bp);
  631.             return -1;
  632.         }
  633. #ifdef PPP_DEBUG_OPTIONS
  634.         if (PPPtrace & PPP_DEBUG_OPTIONS)
  635.             trace_log (PPPiface, "IPCP REQ: result %s, option %d, length %d",
  636.                 fsmCodes[option_result], option.type, option.len);
  637. #endif
  638.         if (option_result < reply_result)
  639.             continue;
  640.         else if (option_result > reply_result) {
  641.             /* Discard current list of replies */
  642.             free_p (reply_bp);
  643.             reply_bp = NULLBUF;
  644.             reply_result = option_result;
  645.         }
  646.         /* remember that we processed option */
  647.         if (option_result != CONFIG_REJ && option.type <= IPCP_OPTION_LIMIT)
  648.             ipcp_p->remote.work.negotiate |= (1 << option.type);
  649.  
  650.         /* Add option response to the return list */
  651.         ipcp_option (&reply_bp, &(ipcp_p->remote.work), option.type, option.len, &data);
  652.     }
  653.  
  654.     /* Now check for any missing options which are desired */
  655.     if (fsm_p->retry_nak > 0 && (desired = ipcp_p->remote.want.negotiate & ~ipcp_p->remote.work.negotiate) != 0) {
  656.         switch (reply_result) {
  657.             case CONFIG_ACK:
  658.                 free_p (reply_bp);
  659.                 reply_bp = NULLBUF;
  660.                 reply_result = CONFIG_NAK;
  661.                 /* fallthru */
  662.             case CONFIG_NAK:
  663.                 ipcp_makeoptions (&reply_bp, &(ipcp_p->remote.want), desired);
  664.                 fsm_p->retry_nak--;
  665.                 break;
  666.             case CONFIG_REJ:
  667.             default:
  668.                 /* do nothing */
  669.                 break;
  670.         }
  671.     } else if (reply_result == CONFIG_NAK) {
  672.         /* if too many NAKs, reject instead */
  673.         if (fsm_p->retry_nak > 0)
  674.             fsm_p->retry_nak--;
  675.         else
  676.             reply_result = CONFIG_REJ;
  677.     }
  678.     /* Send ACK/NAK/REJ to remote host */
  679.     (void) fsm_send (fsm_p, uchar (reply_result), config->id, reply_bp);
  680.     free_p (data);
  681.     return (reply_result != CONFIG_ACK);
  682. }
  683.  
  684.  
  685.  
  686. /************************************************************************/
  687. /* Process configuration ACK sent by remote host */
  688. static int
  689. ipcp_ack (struct fsm_s *fsm_p, struct config_hdr *config, struct mbuf *data)
  690. {
  691. struct mbuf *req_bp;
  692. int error = FALSE;
  693.  
  694.     PPP_DEBUG_ROUTINES ("ipcp_ack()");
  695.  
  696.     /* ID field must match last request we sent */
  697.     if (config->id != fsm_p->lastid) {
  698.         PPP_DEBUG_CHECKS ("IPCP ACK: wrong ID");
  699.         free_p (data);
  700.         return -1;
  701.     }
  702.     /* Get a copy of last request we sent */
  703.     req_bp = ipcp_makereq (fsm_p);
  704.  
  705.     /* Overall buffer length should match */
  706.     if (config->len != len_p (req_bp)) {
  707.         PPP_DEBUG_CHECKS ("IPCP ACK: buffer length mismatch");
  708.         error = TRUE;
  709.     } else {
  710.         register int req_char;
  711.         register int ack_char;
  712.  
  713.         /* Each byte should match */
  714.         while ((req_char = pullchar (&req_bp)) != -1) {
  715.             if ((ack_char = pullchar (&data)) == -1 || ack_char != req_char) {
  716.                 PPP_DEBUG_CHECKS ("IPCP ACK: data mismatch");
  717.                 error = TRUE;
  718.                 break;
  719.             }
  720.         }
  721.     }
  722.     free_p (req_bp);
  723.     free_p (data);
  724.  
  725.     if (error)
  726.         return -1;
  727.  
  728.     PPP_DEBUG_CHECKS ("IPCP ACK: valid");
  729.     return 0;
  730. }
  731.  
  732.  
  733.  
  734. /************************************************************************/
  735. /* Process configuration NAK sent by remote host */
  736. static int
  737. ipcp_nak (struct fsm_s *fsm_p, struct config_hdr *config, struct mbuf *data)
  738. {
  739. struct ipcp_s *ipcp_p = fsm_p->pdv;
  740. struct ipcp_side_s *local_p = &(ipcp_p->local);
  741. int32 signed_length = config->len;
  742. struct option_hdr option;
  743. int last_option = 0;
  744. int result;
  745.  
  746.     PPP_DEBUG_ROUTINES ("ipcp_nak()");
  747.  
  748.     /* ID field must match last request we sent */
  749.     if (config->id != fsm_p->lastid) {
  750.         PPP_DEBUG_CHECKS ("IPCP NAK: wrong ID");
  751.         free_p (data);
  752.         return -1;
  753.     }
  754.     /* First, process in order.  Then, process extra "important" options */
  755.     while (signed_length > 0 && ntohopt (&option, &data) != -1) {
  756.         if ((signed_length -= option.len) < 0) {
  757.             PPP_DEBUG_CHECKS ("IPCP NAK: bad header length");
  758.             free_p (data);
  759.             return -1;
  760.         }
  761.         if (option.type > IPCP_OPTION_LIMIT)
  762.             PPP_DEBUG_CHECKS ("IPCP NAK: option out of range");
  763.         else if (option.type < last_option
  764.                || !(local_p->work.negotiate & (1 << option.type))) {
  765.             if (local_p->work.negotiate & (1 << option.type)) {
  766.                 PPP_DEBUG_CHECKS ("IPCP NAK: option out of order");
  767.                 free_p (data);
  768.                 return -1;    /* was requested */
  769.             }
  770.             local_p->work.negotiate |= (1 << option.type);
  771.             last_option = IPCP_OPTION_LIMIT + 1;
  772.         } else
  773.             last_option = option.type;
  774.  
  775.         if ((result = ipcp_check (&data, ipcp_p, local_p, &option, FALSE)) == -1) {
  776.             PPP_DEBUG_CHECKS ("IPCP NAK: ran out of data");
  777.             free_p (data);
  778.             return -1;
  779.         }
  780.         /* update the negotiation status */
  781.         if (result == CONFIG_REJ && option.type <= IPCP_OPTION_LIMIT)
  782.             local_p->work.negotiate &= ~(1 << option.type);    /*lint !e502 */
  783.     }
  784.     PPP_DEBUG_CHECKS ("IPCP NAK: valid");
  785.     free_p (data);
  786.     return 0;
  787. }
  788.  
  789.  
  790.  
  791. /************************************************************************/
  792. /* Process configuration reject sent by remote host */
  793. static int
  794. ipcp_reject (struct fsm_s *fsm_p, struct config_hdr *config, struct mbuf *data)
  795. {
  796. struct ipcp_s *ipcp_p = fsm_p->pdv;
  797. struct ipcp_side_s *local_p = &(ipcp_p->local);
  798. int32 signed_length = config->len;
  799. struct option_hdr option;
  800. int last_option = 0;
  801.  
  802.     PPP_DEBUG_ROUTINES ("ipcp_reject()");
  803.  
  804.     /* ID field must match last request we sent */
  805.     if (config->id != fsm_p->lastid) {
  806.         PPP_DEBUG_CHECKS ("IPCP REJ: wrong ID");
  807.         free_p (data);
  808.         return -1;
  809.     }
  810.     /* Process in order, checking for errors */
  811.     while (signed_length > 0 && ntohopt (&option, &data) != -1) {
  812.         register int k;
  813.  
  814.         if ((signed_length -= option.len) < 0) {
  815.             PPP_DEBUG_CHECKS ("IPCP REJ: bad header length");
  816.             free_p (data);
  817.             return -1;
  818.         }
  819.         if (option.type > IPCP_OPTION_LIMIT)
  820.             PPP_DEBUG_CHECKS ("IPCP REJ: option out of range");
  821.         else if (option.type < last_option || !(local_p->work.negotiate & (1 << option.type))) {
  822.             PPP_DEBUG_CHECKS ("IPCP REJ: option out of order");
  823.             free_p (data);
  824.             return -1;
  825.         }
  826.         for (k = option.len - OPTION_HDR_LEN; k-- > 0;) {
  827.             if (pullchar (&data) == -1) {
  828.                 PPP_DEBUG_CHECKS ("IPCP REJ: ran out of data");
  829.                 free_p (data);
  830.                 return -1;
  831.             }
  832.         }
  833.         last_option = option.type;
  834.  
  835.         if (option.type <= IPCP_OPTION_LIMIT)
  836.             local_p->work.negotiate &= ~(1 << option.type);    /*lint !e502 */
  837.     }
  838.     PPP_DEBUG_CHECKS ("IPCP REJ: valid");
  839.     free_p (data);
  840.     return 0;
  841. }
  842.  
  843.  
  844.  
  845. /************************************************************************/
  846. /*            I N I T I A L I Z A T I O N            */
  847. /************************************************************************/
  848.  
  849. /* Reset configuration options before request */
  850. static void
  851. ipcp_reset (struct fsm_s *fsm_p)
  852. {
  853. struct ipcp_s *ipcp_p = fsm_p->pdv;
  854.  
  855.     PPP_DEBUG_ROUTINES ("ipcp_reset()");
  856.  
  857.     ASSIGN (ipcp_p->local.work, ipcp_p->local.want);
  858.     ipcp_p->local.work.other = ipcp_p->remote.want.address;
  859.     ipcp_p->local.will_negotiate |= ipcp_p->local.want.negotiate;
  860.  
  861.     ipcp_p->remote.work.negotiate = FALSE;
  862.     ipcp_p->remote.will_negotiate |= ipcp_p->remote.want.negotiate;
  863. }
  864.  
  865.  
  866.  
  867. /************************************************************************/
  868. /* After termination */
  869. static void
  870. ipcp_stopping (struct fsm_s *fsm_p OPTIONAL)
  871. {
  872.     PPP_DEBUG_ROUTINES ("ipcp_stopping()");
  873. }
  874.  
  875.  
  876.  
  877. /************************************************************************/
  878. /* Close IPCP */
  879. static void
  880. ipcp_closing (struct fsm_s *fsm_p)
  881. {
  882. struct ipcp_s *ipcp_p = fsm_p->pdv;
  883.  
  884.     /* free old slhc configuration, if any */
  885.     slhc_free (ipcp_p->slhcp);
  886.     ipcp_p->slhcp = NULL;
  887.  
  888. #ifdef notdef
  889.     if (PPPtrace > 1)
  890.         trace_log (PPPiface, "%s PPP/IPCP Drop route to peer (%s)",
  891.             ifp->name, inet_ntoa (ipcp_p->local.work.other));
  892.  
  893.     rt_drop (ipcp_p->local.work.other, (unsigned int) 32);
  894. #endif
  895. }
  896.  
  897.  
  898.  
  899. /************************************************************************/
  900. /* configuration negotiation complete */
  901. static void
  902. ipcp_opening (struct fsm_s *fsm_p)
  903. {
  904. struct ipcp_s *ipcp_p = fsm_p->pdv;
  905. struct iface *ifp = fsm_p->ppp_p->iface;
  906. uint32 address = ipcp_p->local.work.address;
  907. int rslots = 0;
  908. int tslots = 0;
  909.  
  910.     /* Set our IP address to reflect negotiated option */
  911.     if (address != ifp->addr) {
  912.         /* address not the same as last time */
  913.         if (Ip_addr == 0L)
  914.             /* no global address */
  915.             Ip_addr = address;
  916.         else if (Ip_addr == ifp->addr)
  917.             /* global was same as local; must be replaced */
  918.             /* !!! TO DO: reset tcp connections */
  919.             Ip_addr = address;
  920.  
  921.         ifp->addr = address;
  922.  
  923.         if (PPPtrace > 1)
  924.             trace_log (PPPiface, "%s PPP/IPCP Setting new IP address: %s",
  925.                 ifp->name, inet_ntoa (address));
  926.     }
  927. #ifdef notdef
  928.     rt_add (ipcp_p->local.work.other, (unsigned int) 32, (int32) 0, ifp, (int32) 1, (int32) 0, (char) 1);
  929.  
  930.     if (PPPtrace > 1)
  931.         trace_log (PPPiface, "%s PPP/IPCP Add route to peer (%s)",
  932.             ifp->name, inet_ntoa (ipcp_p->local.work.other));
  933. #endif
  934.  
  935.     /* free old slhc configuration, if any */
  936.     slhc_free (ipcp_p->slhcp);
  937.     ipcp_p->slhcp = NULL;
  938.  
  939.     if (ipcp_p->local.work.negotiate & IPCP_N_COMPRESS)
  940.         rslots = ipcp_p->local.work.slots;
  941.  
  942.     if (ipcp_p->remote.work.negotiate & IPCP_N_COMPRESS)
  943.         tslots = ipcp_p->remote.work.slots;
  944.  
  945.     if (rslots != 0 || tslots != 0) {
  946.         ipcp_p->slhcp = slhc_init (rslots, tslots);
  947.  
  948.         if (PPPtrace > 1)
  949.             trace_log (PPPiface, "%s PPP/IPCP Compression enabled; Recv slots = %d, flag = %x;"
  950.                 " Xmit slots = %d, flag = %x", ifp->name, rslots,
  951.                 ipcp_p->local.work.slot_compress, tslots, ipcp_p->remote.work.slot_compress);
  952.     }
  953. }
  954.  
  955.  
  956.  
  957. /************************************************************************/
  958. /* Check the address against all other assigned addresses */
  959. static uint32
  960. ipcp_addr_idle (uint32 addr)
  961. {
  962. struct iface *ifp;
  963.  
  964.     /* Check if peer IP address is already in use on another interface */
  965.     /* !!! need to look at *remote* address, not local! */
  966.     for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
  967.         if (ifp->addr == addr)
  968.             return 0L;
  969.     }
  970.     return addr;
  971. }
  972.  
  973.  
  974.  
  975. /************************************************************************/
  976. /* Assign the next unused address from a pool */
  977. static uint32
  978. ipcp_poolnext (struct ipcp_s *ipcp_p)
  979. {
  980. uint32 i = 1L + ipcp_p->peer_max - ipcp_p->peer_min;
  981. uint32 nextaddr = 0L;
  982.  
  983.     while (i-- > 0 && nextaddr == 0L) {
  984.         if (++ipcp_p->local.want.other < ipcp_p->peer_min
  985.             || ipcp_p->local.want.other > ipcp_p->peer_max)
  986.             ipcp_p->local.want.other = ipcp_p->peer_min;
  987.  
  988.         nextaddr = ipcp_addr_idle (ipcp_p->local.want.other);
  989.     }
  990.     return (nextaddr);
  991. }
  992.  
  993.  
  994.  
  995. /************************************************************************/
  996. /* Check if we have a specific IP address to assign to remote peer host */
  997. /* !!! TO DO: subnet mask, and routing */
  998. static uint32
  999. ipcp_lookuppeer (char *peerid)
  1000. {
  1001. char *buf;
  1002. uint32 peer_addr = 0L;
  1003.  
  1004.     if (peerid == NULLCHAR)
  1005.         return 0L;
  1006.  
  1007.     if ((buf = userlookup (peerid, NULLCHARP, NULLCHARP, NULL, &peer_addr)) != NULLCHAR)
  1008.         free (buf);
  1009.  
  1010.     return (peer_addr);
  1011. }
  1012.  
  1013.  
  1014.  
  1015. /************************************************************************/
  1016. /* Prepare to begin configuration exchange */
  1017. static void
  1018. ipcp_starting (struct fsm_s *fsm_p)
  1019. {
  1020. struct ipcp_s *ipcp_p = fsm_p->pdv;
  1021.  
  1022.     PPP_DEBUG_ROUTINES ("ipcp_starting()");
  1023.  
  1024.     /* If not already set, and we know the name of the peer,
  1025.      * look in login file for an address
  1026.      */
  1027.     if (ipcp_p->remote.want.address == 0L)
  1028.         ipcp_p->remote.want.address = ipcp_lookuppeer (fsm_p->ppp_p->peername);
  1029.  
  1030.     /* If available, get next address from PPP pool */
  1031.     if ((ipcp_p->remote.want.address == 0L) && (ipcp_p->peer_min != 0L))
  1032.         ipcp_p->remote.want.address = ipcp_poolnext (ipcp_p);
  1033.  
  1034.     ipcp_p->local.want.address = fsm_p->ppp_p->iface->addr;
  1035. }
  1036.  
  1037.  
  1038.  
  1039. /************************************************************************/
  1040. static void
  1041. ipcp_free (struct fsm_s *fsm_p)
  1042. {
  1043. struct ipcp_s *ipcp_p = fsm_p->pdv;
  1044.  
  1045.     slhc_free (ipcp_p->slhcp);
  1046. }
  1047.  
  1048.  
  1049.  
  1050. /* Initialize configuration structure */
  1051. void
  1052. ipcp_init (struct ppp_s *ppp_p)
  1053. {
  1054. struct fsm_s *fsm_p = &(ppp_p->fsm[IPcp]);
  1055. struct ipcp_s *ipcp_p;
  1056.  
  1057.     PPPtrace = ppp_p->trace;
  1058.     PPPiface = ppp_p->iface;
  1059.  
  1060.     PPP_DEBUG_ROUTINES ("ipcp_init()");
  1061.  
  1062.     fsm_p->ppp_p = ppp_p;
  1063.     fsm_p->pdc = &ipcp_constants;
  1064.     fsm_p->pdv = ipcp_p = callocw (1, sizeof (struct ipcp_s));
  1065.  
  1066.     /* Set option parameters to first request defaults */
  1067.     ASSIGN (ipcp_p->local.want, ipcp_default);
  1068.     ipcp_p->local.will_negotiate = ipcp_negotiate;
  1069.  
  1070.     ASSIGN (ipcp_p->remote.want, ipcp_default);
  1071.     ASSIGN (ipcp_p->remote.work, ipcp_default);
  1072.     ipcp_p->remote.will_negotiate = ipcp_negotiate;
  1073.  
  1074.     fsm_init (fsm_p);
  1075. }
  1076.  
  1077.  
  1078. #endif /* PPP */
  1079.